package model

import (
	"fmt"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"

	"gitee.com/goframe/lt-collector/libs/orma"
	"gitee.com/goframe/lt-collector/model/tool"
)

const (
	//TimeZone 中国时区
	TimeZone = "Asia/Shanghai"
	//时间格式
	TimeLayout = "2006-01-02 15:04:05"
	//日期格式
	dateFormat = "2006-01-02"
	//期号格式
	issueDateFormat = "20060102"

	//期号累加1
	issueAddOneType = iota
	//以日期作为期号类型
	//A:开奖时间的日期等于期号的日期
	//B:第一期时间为特殊指定时间,期号日期在指定时间前的为前一天日期;期号日期在指定时间后的为当日日期;
	issueDateTypeA
	issueDateTypeB
)

//stringToTodayTime 00:00:00 格式 解析到当日时间
func stringToTodayTime(str string) time.Time {
	f := time.Now().Format(dateFormat) + " " + str
	t, _ := time.ParseInLocation(TimeLayout, f, time.Local)
	return t
}

//issueFormatType return lotto issue date format type
func (m *GameIssuePlan) issueFormatType() int {
	if m.IssueAddOne {
		return issueAddOneType
	}
	if m.firstTime().After(m.lastTime()) {
		return issueDateTypeB
	}
	return issueDateTypeA
}

//firstTime return lotto first start issue time
func (m *GameIssuePlan) firstTime() time.Time {
	return stringToTodayTime(m.FirstIssueTime)
}

//lastTime return lotto last issue time
func (m *GameIssuePlan) lastTime() time.Time {
	return stringToTodayTime(m.LastIssueTime)
}

//addOneTypeIssue get addOneType lotto's issue and nextIssue
func (m *GameIssuePlan) addOneTypeIssue(timeList tool.TimeList, openData *OpenData) (err error) {
	defer func() {
		if p := recover(); p != nil {
			err = fmt.Errorf("error:[addOneTypeIssue]|info:%s|openData:%#v", p, openData)
		}
	}()
	var checkIssueNum int
	check := &GameIssueCheck{Gid: m.Gid}
	if err = orma.NormalGet(m.Session().Get(check)); err != nil {
		return
	}
	checkIssueNum, err = strconv.Atoi(check.Issue)
	if err != nil {
		return
	}
	f := m.firstTime()
	//获取当前开奖序号
	//可能产生的错误:当最后一期的时间在第一期时间之前,就会出错
	var thisIndex int
	if time.Now().Before(f) {
		thisIndex = 0
	} else {
		thisIndex = timeList.GetIndex(f, openData.OpenTime.Convert2Time())
	}
	mps := map[string]interface{}{
		"check":     check,
		"thisIndex": thisIndex,
	}
	//计算今日0点距离校对时间0点的天数
	zeroStringToday := fmt.Sprintf("%s 00:00:00", time.Now().Format(dateFormat))
	zeroStringCheckOpenTime := fmt.Sprintf("%s 00:00:00", check.OpenTime.Convert2Time().Format(dateFormat))
	var (
		zeroToday, zeroCheckOpenTime time.Time
	)
	zeroToday, _ = time.ParseInLocation(TimeLayout, zeroStringToday, time.Local)
	zeroCheckOpenTime, _ = time.ParseInLocation(TimeLayout, zeroStringCheckOpenTime, time.Local)
	days := int(zeroToday.Sub(zeroCheckOpenTime).Hours() / 24)
	mps["days"] = days
	//获取校对时间对于今日的序号
	checkIndex := timeList.GetIndex(f, stringToTodayTime(check.OpenTime.Convert2Time().Format("15:04:05")))
	mps["checkIndex"] = checkIndex
	checkIssueNum = checkIssueNum - checkIndex + days*len(timeList) + thisIndex

	openData.OtherData = mps
	openData.Issue = strconv.Itoa(checkIssueNum)
	openData.NextIssue = strconv.Itoa(checkIssueNum + 1)
	return
}

//ParseIssueAndTime parse lotto to a OpenData,without OpenCode
func (m *GameIssuePlan) ParseIssueAndTime() (openData *OpenData, err error) {
	defer func() {
		if p := recover(); p != nil {
			err = fmt.Errorf("error:[ParseIssueAndTime]|info:%v|openData:%#v", p, openData)
		}
	}()
	openData = &OpenData{Gid: m.Gid}
	timeList := new(OpenTimePlan).getAllTimeList(m.TimePlans)
	prevTime := timeList.PrevTime()
	nextTime := timeList.CurrentTime()
	openData.OpenTime = new(orma.JSONTime)
	openData.OpenTime.SetByTime(prevTime)
	openData.OpenTimestamp = prevTime.Unix()
	openData.NextOpenTime = new(orma.JSONTime)
	openData.NextOpenTime.SetByTime(nextTime)
	openData.NextOpenTimestamp = nextTime.Unix()
	firstTime := m.firstTime()
	var prevIssueDate, nextIssueDate string
	switch m.issueFormatType() {
	case issueAddOneType:
		err = m.addOneTypeIssue(timeList, openData)
		return
	case issueDateTypeA:
		prevIssueDate = prevTime.Format(issueDateFormat)
		nextIssueDate = nextTime.Format(issueDateFormat)
	case issueDateTypeB:
		if prevTime.Before(firstTime) && prevTime.Day() == firstTime.Day() {
			prevIssueDate = prevTime.AddDate(0, 0, -1).Format(issueDateFormat)
		} else {
			prevIssueDate = prevTime.Format(issueDateFormat)
		}
		if nextTime.Before(firstTime) || nextTime.Day() != firstTime.Day() {
			nextIssueDate = nextTime.AddDate(0, 0, -1).Format(issueDateFormat)
		} else {
			nextIssueDate = nextTime.Format(issueDateFormat)
		}
	}
	if len(prevIssueDate) > 0 {
		openData.Issue = prevIssueDate + timeList.FormatIssueSuffix(timeList.GetIndex(firstTime, prevTime))
	}
	if len(nextIssueDate) > 0 {
		openData.NextIssue = nextIssueDate + timeList.FormatIssueSuffix(timeList.GetIndex(firstTime, nextTime))
	}
	return
}

//getTimeList return a timeList
func (m *OpenTimePlan) getTimeList() (list tool.TimeList) {
	if m.PeriodSeconds < 10 {
		panic("彩种开奖周期时间小于10秒")
	}
	ts := stringToTodayTime(m.Start)
	tt := stringToTodayTime(m.Stop)
	if ts.After(tt) {
		tt = tt.Add(time.Hour * 24)
	}
	list = make(tool.TimeList, 0, 1)
	for {
		if ts.After(tt) {
			break
		}
		var addTime = ts
		if addTime.Day() != time.Now().Day() {
			addTime = addTime.AddDate(0, 0, -1)
		}
		list = append(list, addTime)
		ts = ts.Add(time.Second * time.Duration(m.PeriodSeconds))
	}
	return
}

//getAllTimeList return all timeList by a plan slice
func (m *OpenTimePlan) getAllTimeList(plans []OpenTimePlan) (list tool.TimeList) {
	list = make(tool.TimeList, 0)
	for _, plan := range plans {
		list = append(list, plan.getTimeList()...)
	}
	return
}

//CheckTimePlan 校对当日期号总数与设置的时间计划是否一致
func (m *OpenTimePlan) CheckTimePlan(issueLenOneDay int, plans []OpenTimePlan) (err error) {
	list := m.getAllTimeList(plans)
	if issueLenOneDay != len(list) {
		return fmt.Errorf("设置的时间计划每天开奖总数为:%d,请检查设置", len(list))
	}
	return
}

//OpenTimeList ...
func (m *GameIssuePlan) OpenTimeList() (planMap []gin.H) {
	plan := new(OpenTimePlan)
	list1 := plan.getAllTimeList(m.TimePlans)
	planMap = make([]gin.H, 0, len(list1))
	for i, value := range list1 {
		planMap = append(planMap, gin.H{"index": list1.FormatIssueSuffix(i + 1), "time": orma.JSONTime(value)})
	}
	return
}
